package com.idp.common.persistence;

import java.lang.reflect.InvocationTargetException;
import java.util.Date;
import java.util.Map;
import java.util.Properties;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.plugin.Signature;
import org.apache.log4j.Logger;

import com.idp.common.constant.SessionAttr;
import com.idp.common.util.ContextHolderUtil;
import com.idp.common.util.ResourceUtils;
import com.idp.web.system.entity.SysUser;

/**
 * 添加/更新拦截器: 给各实体对象在增加、修改时，自动添加操作属性信息
 * @author WuJiangWu
 * @date 2018年4月21日下午11:53:20
 */
@Intercepts({ @Signature(type = Executor.class, method = "update", args = { MappedStatement.class, Object.class }) })
public class SaveInterceptor implements Interceptor {

	private final static Logger logger = Logger.getLogger(SaveInterceptor.class);
	
	public Object intercept(Invocation invocation) throws Throwable {
		Object[] args = invocation.getArgs();
		
		SqlCommandType type = null;//操作类型
		// 遍历处理所有参数，update方法有两个参数，参见Executor类中的update()方法。
		for (int i = 0; i < args.length; i++) {
			Object arg = args[i];
			// 第一个参数处理。根据它判断是否给“操作属性”赋值。
			if (arg instanceof MappedStatement) {// 如果是第一个参数 MappedStatement
				MappedStatement ms = (MappedStatement) arg;
				SqlCommandType sqlCommandType = ms.getSqlCommandType();
				// 如果不是添加或更新操作直接返回
				if (sqlCommandType != SqlCommandType.INSERT && sqlCommandType != SqlCommandType.UPDATE) {
					return invocation.proceed();
				}else{
					type = sqlCommandType;
					continue;
				}
			}
			logger.info("-----------["+type+"]操作拦截begin---------------------------------------------------");
			// 第二个参数处理 
			// 如果是map，有两种情况：（1）使用@Param多参数传入，由Mybatis包装成map。（2）原始传入Map
			String className = arg.getClass().getName();
			logger.info("操作类型：" + type +"\t实体类型：" + className);
			if (arg instanceof Map) {
				logger.info("这是一个包装过的类型!");
				Map map = (Map) arg;
				for (Object obj : map.values()) {
					setProperty(obj,type);
				}
			} else {// 原始参数传入
				setProperty(arg,type);
			}
			logger.info("-----------["+type+"]操作拦截end---------------------------------------------------");
		}
		return invocation.proceed();
	}

	/**
	 * 为对象的操作属性赋值
	 * @param obj
	 * @param type
	 */
	private void setProperty(Object obj, SqlCommandType type) {
		try {
			if(type == null){
				return;
			}
			SysUser user = (SysUser) ContextHolderUtil.getSession().getAttribute(SessionAttr.USER_LOGIN.getValue());
			//添加操作
			if (type == SqlCommandType.INSERT) {
				BeanUtils.setProperty(obj, "id", ResourceUtils.getUUID());
				BeanUtils.setProperty(obj, "delFlag", "0");//1为删除0为正常
				BeanUtils.setProperty(obj, "createUser", user.getId());
				BeanUtils.setProperty(obj, "createUserName", user.getUsername());
				BeanUtils.setProperty(obj, "createDate", new Date());
			//更新操作
			}else if(type != SqlCommandType.UPDATE){
				BeanUtils.setProperty(obj, "updateUser", user.getId());
				BeanUtils.setProperty(obj, "updateUserName", user.getUsername());
				BeanUtils.setProperty(obj, "updateDate", new Date());
			}
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		}
	}

	public Object plugin(Object target) {
		return Plugin.wrap(target, this);
	}

	public void setProperties(Properties properties) {

	}

}